package com.oak.broke.utils.sm4;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author wangqiaosheng
 * @version: V1.0.0
 * @description SM4解密工具
 */
@Slf4j
public class SM4Util {

    private static String XT_VAL_EMPTY = "";
    private static String XT_VAL_SPECIAL_CHARACTERS_COMMA = ",";

    private static String XT_CHARACTER_ENCODING_UTF8 = "UTF-8";

    private static boolean hexString = true;

    private static final String SECRETKEY = "20EC2C063AB7CF64R2D04FF83A316915";

    public SM4Util() {
    }

    /**
     * 获取加密后值
     *
     * @param val 预加密数据
     * @return
     */
    public static String getEncryptVal(String val) throws Exception {
        if (XT_VAL_EMPTY.equals(StringUtils.trim(val))) {
            return XT_VAL_EMPTY;
        }
        return encryptDataECB(val);
    }

    /**
     * 获取解密后值
     *
     * @param val 预解密数据
     * @return
     */
    public static String getDecryptVal(String val) throws Exception {
        if (XT_VAL_EMPTY.equals(StringUtils.trim(val))) {
            return XT_VAL_EMPTY;
        }
        return decryptDataECB(val);
    }

    /**
     * 加密
     *
     * @param plainText
     * @return
     */
    public static String encryptDataECB(String plainText) throws Exception {
        if (XT_VAL_EMPTY.equals(StringUtils.trim(plainText))) {
            return plainText;
        }
        SM4Context ctx = new SM4Context();
        ctx.isPadding = true;
        ctx.mode = SM4.SM4_ENCRYPT;
        byte[] keyBytes;
        if (hexString) {
            keyBytes = Util.hexStringToBytes(SECRETKEY);
        } else {
            keyBytes = Util.hexStringToBytes(SECRETKEY);
        }
        SM4 sm4 = new SM4();
        sm4.sm4SetkeyEnc(ctx, keyBytes);
        String sm4Data = null;
        if (plainText.contains(XT_VAL_SPECIAL_CHARACTERS_COMMA)) {
            String[] plainTextArr = plainText.split(XT_VAL_SPECIAL_CHARACTERS_COMMA);
            String[] plainTextSm4Arr = new String[plainTextArr.length];
            for (int i = 0; i < plainTextArr.length; i++) {
                byte[] encrypted = sm4.sm4CryptEcb(ctx, plainTextArr[i].getBytes(XT_CHARACTER_ENCODING_UTF8));
                plainTextSm4Arr[i] = Util.byteToHex(encrypted);
            }
            sm4Data = StringUtils.join(plainTextSm4Arr, ",");
        } else {
            byte[] encrypted = sm4.sm4CryptEcb(ctx, plainText.getBytes(XT_CHARACTER_ENCODING_UTF8));
            sm4Data = Util.byteToHex(encrypted);
        }
        log.info("加密后：{},加密前:{},秘钥:{},", sm4Data, plainText, SECRETKEY);
        return sm4Data;
    }

    /**
     * 解密
     *
     * @param cipherText
     * @return
     */
    public static String decryptDataECB(String cipherText) throws Exception {
        if (StringUtils.isBlank(cipherText)) {
            return cipherText;
        }
        if (cipherText.length() < 32) {
            throw new Exception("非加密数据");
        }
        String sm4Data = null;
        if (cipherText.contains(XT_VAL_SPECIAL_CHARACTERS_COMMA)) {
            String[] plainTextArr = cipherText.split(XT_VAL_SPECIAL_CHARACTERS_COMMA);
            String[] plainTextSm4Arr = new String[plainTextArr.length];
            for (int i = 0; i < plainTextArr.length; i++) {
                plainTextSm4Arr[i] = decryptDataECBOPT(plainTextArr[i], SECRETKEY);
            }
            sm4Data = StringUtils.join(plainTextSm4Arr, XT_VAL_SPECIAL_CHARACTERS_COMMA);
        } else {
            sm4Data = decryptDataECBOPT(cipherText, SECRETKEY);
        }
        return sm4Data;
    }

    /**
     * 解密 扩展使用
     *
     * @param cipherText
     * @return
     */
    public static String decryptDataECBOPT(String cipherText, String secretKey) throws Exception {
        byte[] encrypted = Util.hexToByte(cipherText);
        cipherText = Base64.encodeBase64String(encrypted);
        ;
        if (cipherText != null && cipherText.trim().length() > 0) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(cipherText);
            cipherText = m.replaceAll(XT_VAL_EMPTY);
        }
        SM4Context ctx = new SM4Context();
        ctx.isPadding = true;
        ctx.mode = SM4.SM4_DECRYPT;
        byte[] keyBytes;
        if (hexString) {
            keyBytes = Util.hexStringToBytes(secretKey);
        } else {
            keyBytes = secretKey.getBytes();
        }
        SM4 sm4 = new SM4();
        sm4.sm4SetkeyDec(ctx, keyBytes);
        byte[] decrypted = sm4.sm4CryptEcb(ctx, Base64.decodeBase64(cipherText));
        return new String(decrypted, XT_CHARACTER_ENCODING_UTF8);
    }


    public static void main(String[] args) {
        try {
            String plainText = "320124199405262212422225412";
            SM4Util sm4 = new SM4Util();
            long cureentTime = System.currentTimeMillis();
            String cipherText = encryptDataECB(plainText);
            long useTime = System.currentTimeMillis() - cureentTime;
            log.warn("ECB模式加密，加密耗时：" + useTime + "毫秒");
            log.warn("ECB模式加密，密文: " + cipherText);
            cureentTime = System.currentTimeMillis();
            String plainText2 = decryptDataECB(cipherText);
            useTime = System.currentTimeMillis() - cureentTime;
            log.warn("明文: " + plainText2);
            log.warn("ECB模式解密，解密耗时：" + useTime + "毫秒");
        } catch (Exception e) {
            log.error("加解密异常！");
        }


    }
}
